package game;

/**
 *	@(#)GameFlow.java
 *
 *	The <code>GameFlow</code> class represents the game phases.
 *	It also manages the turn order.
 *
 *	@author Grzegorz Kobiela
 *	@version 2.0 2008/5/12
 */
public final class GameFlow
extends GameObject
{
	/** Constant representing the begin of a phase. */
	public static final int PHASE_BEGIN = 0;

	/** Constant representing the duration of a phase. */
	public static final int PHASE_PERFORM = 1;

	/** Constant representing the end of a phase. */
	public static final int PHASE_END = 2;

	/** The individual phases. */
	public enum Phase
	{
		PREPARATION,
		ALL_RISE,
		CITY_BUILDING,
		TURN_ORDER,
		LAND_BUILDING,
		STORAGE,
		HARVEST,
		EXPLORATION,
		FAMINE,
		POLLUTION,
		CHECK_VICTORY,
		GAME_END;

		/**
		 *	Returns the phase following the given one.
		 *	@return the next phase
		 */
		public Phase next() {
			switch(this) {
				case PREPARATION: return ALL_RISE;
				case ALL_RISE: return CITY_BUILDING;
				case CITY_BUILDING: return TURN_ORDER;
				case TURN_ORDER: return LAND_BUILDING;
				case LAND_BUILDING: return STORAGE;
				case STORAGE: return HARVEST;
				case HARVEST: return EXPLORATION;
				case EXPLORATION: return FAMINE;
				case FAMINE: return POLLUTION;
				case POLLUTION: return CHECK_VICTORY;
				case CHECK_VICTORY: return ALL_RISE;
				default: return null;
			}
		}
	}

	/** The current round. */
	private int round;

	/** The current phase. */
	private Phase phase;

	/** The previous phase. */
	private Phase previous;

	/** The turn order object. */
	private TurnOrder turnOrder;

	/**
	 *	Creates a new <code>GameFlow</code> instance.
	 */
	public GameFlow() {
		turnOrder = new TurnOrder();
	}

	/**
	 *	Returns true if the current phase is a land phase.
	 *	@return true if the current phase is a land phase
	 */
	public boolean isLandPhase() {
		return (
			phase.equals(Phase.PREPARATION) ||
			phase.equals(Phase.TURN_ORDER) ||
			phase.equals(Phase.LAND_BUILDING) ||
			phase.equals(Phase.HARVEST) ||
			phase.equals(Phase.EXPLORATION) ||
			phase.equals(Phase.POLLUTION) ||
			phase.equals(Phase.CHECK_VICTORY) ||
			phase.equals(Phase.GAME_END)
		);
	}

	/**
	 *	Returns true if the game is over.
	 *	@return true if the game is over
	 */
	public boolean isOver() {
		return phase.equals(Phase.GAME_END);
	}

	/**
	 *	This method is called at game start.
	 *	It initializes the <code>phase</code> field and
	 *	notifies the observers that the game has started.
	 */
	public void start() {
		round = 0;
		phase = Phase.PREPARATION;
		previous = null;
		turnOrder.reset(-1);
		update(PHASE_BEGIN);
	}

	/**
	 *	This method is called at game end.
	 *	It resets the <code>phase</code> field.
	 */
	public void end() {
		phase = Phase.GAME_END;
		previous = null;
		update(PHASE_PERFORM);
	}

	/**
	 *	Returns the current round.
	 *	@return the current round
	 */
	public int getRound() {
		return round;
	}

	/**
	 *	Returns the current phase.
	 *	@return the current phase
	 */
	public Phase getPhase() {
		return phase;
	}

	/**
	 *	Returns the previous phase.
	 *	@return the previous phase
	 */
	public Phase getPrevious() {
		return previous;
	}

	/**
	 *	Increases the phase by one and notifies the observers.
	 *	If that number exceeds the maximum, it will be reset.
	 */
	public void nextPhase() {
		if(phase.equals(Phase.ALL_RISE)) round++;
		previous = phase;
		phase = phase.next();
		turnOrder.reset();
		update(PHASE_END);
	}

	/**
	 *	Returns the turn order object.
	 *	@return the turn order
	 */
	public TurnOrder getTurnOrder() {
		return turnOrder;
	}

	/**
	 *	Sets the turn order to the given value.
	 *	@param order the new turn order
	 */
	public void setTurnOrder(java.util.ArrayList<Integer> order) {
		turnOrder.setOrder(order);
		update(turnOrder);
	}

	/**
	 *	Returns the index of the active player.
	 *	@return the index of the active player
	 */
	public int getTurn() {
		return turnOrder.getCurrent();
	}

	/**
	 *	Increases the turn by one and notifies the observers.
	 *	Only in phase 0 the turn will be decreased by this method.
	 */
	public void nextTurn() {
		if(phase.equals(Phase.PREPARATION)) {
			turnOrder.prev();
		} else {
			turnOrder.next();
		}
		if(turnOrder.isValid()) {
			update(PHASE_PERFORM);
		} else {
			nextPhase();
		}
	}

	/**
	 *	Repeats a player's turn.
	 */
	public void repeatTurn() {
		update(PHASE_PERFORM);
	}
}